package model

import (
	"context"
	"database/sql"
	"fmt"
	"probe-users/internal/errorx"

	"github.com/zeromicro/go-zero/core/stores/cache"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"github.com/zeromicro/go-zero/core/syncx"
)

var _ UserModel = (*customUserModel)(nil)

type (
	// UserModel 接口定义
	UserModel interface {
		userModel
		FindByUsername(username string) (*User, error)
		FindByEmail(email string) (*User, error)
		FindByPhone(phone string) (*User, error)
	}

	customUserModel struct {
		*defaultUserModel
	}
)

const (
	userTable = "users"
)

var userRows = "`id`, `username`, `password`, `email`, `phone`, `nickname`, `role_id`, `created_at`, `updated_at`, `deleted_at`"

type userModel interface {
	Insert(data *User) (sql.Result, error)
	FindOne(id int64) (*User, error)
	Update(data *User) error
	Delete(id int64) error
	Count(ctx context.Context) (int64, error)
	FindPage(ctx context.Context, offset, limit int) ([]*User, error)
}

type defaultUserModel struct {
	conn  sqlx.SqlConn
	cache cache.Cache
	table string
}

// NewUserModel 创建用户模型实例
func NewUserModel(conn sqlx.SqlConn, c cache.CacheConf) UserModel {
	return &customUserModel{
		defaultUserModel: newDefaultUserModel(conn, c),
	}
}

// FindByUsername 通过用户名查询用户
func (m *customUserModel) FindByUsername(username string) (*User, error) {
	user := new(User)
	query := fmt.Sprintf("select %s from %s where username = ? limit 1", userRows, m.table)
	err := m.QueryRowNoCache(user, query, username)
	switch err {
	case nil:
		return user, nil
	case sql.ErrNoRows:
		return nil, fmt.Errorf("%w: 用户名 %s 不存在", errorx.ErrUserNotFound, username)
	default:
		return nil, err
	}
}

// FindByEmail 通过邮箱查询用户
func (m *customUserModel) FindByEmail(email string) (*User, error) {
	user := new(User)
	query := fmt.Sprintf("select %s from %s where email = ? limit 1", userRows, m.table)
	err := m.QueryRowNoCache(user, query, email)
	switch err {
	case nil:
		return user, nil
	case sql.ErrNoRows:
		return nil, fmt.Errorf("%w: 邮箱 %s 不存在", errorx.ErrUserNotFound, email)
	default:
		return nil, err
	}
}

// FindByPhone 通过手机号查询用户
func (m *customUserModel) FindByPhone(phone string) (*User, error) {
	user := new(User)
	query := fmt.Sprintf("select %s from %s where phone = ? limit 1", userRows, m.table)
	err := m.QueryRowNoCache(user, query, phone)
	switch err {
	case nil:
		return user, nil
	case sql.ErrNoRows:
		return nil, fmt.Errorf("%w: 用户手机号 %s 不存在", errorx.ErrUserNotFound, phone)
	default:
		return nil, err
	}
}

func newDefaultUserModel(conn sqlx.SqlConn, c cache.CacheConf) *defaultUserModel {
	return &defaultUserModel{
		conn:  conn,
		cache: cache.New(c, syncx.NewSingleFlight(), cache.NewStat("role"), errorx.ErrRoleNotFound),
		table: userTable,
	}
}

func (m *defaultUserModel) Insert(data *User) (sql.Result, error) {
	query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?,?)", m.table, userRows)
	return m.conn.Exec(query, data.ID, data.Username, data.Password, data.Email, data.Phone, data.Nickname, data.RoleID, data.CreatedAt, data.UpdatedAt, data.DeletedAt)
}

func (m *defaultUserModel) FindOne(id int64) (*User, error) {
	user := new(User)
	query := fmt.Sprintf("select %s from %s where id = ? limit 1", userRows, m.table)
	err := m.QueryRowNoCache(user, query, id)
	switch err {
	case nil:
		return user, nil
	case sql.ErrNoRows:
		return nil, fmt.Errorf("%w: 用户ID %d 不存在", errorx.ErrUserNotFound, id)
	default:
		return nil, err
	}
}

func (m *defaultUserModel) Update(data *User) error {
	query := fmt.Sprintf("update %s set %s where id = ?", m.table, "`username`=?, `password`=?, `email`=?, `phone`=?, `nickname`=?, `role_id`=?, `created_at`=?, `updated_at`=?, `deleted_at`=?")
	_, err := m.conn.Exec(query, data.Username, data.Password, data.Email, data.Phone, data.Nickname, data.RoleID, data.CreatedAt, data.UpdatedAt, data.DeletedAt, data.ID)
	return err
}

func (m *defaultUserModel) Delete(id int64) error {
	query := fmt.Sprintf("delete from %s where id = ?", m.table)
	_, err := m.conn.Exec(query, id)
	return err
}

func (m *defaultUserModel) QueryRowNoCache(dest interface{}, query string, args ...interface{}) error {
	return m.conn.QueryRow(dest, query, args...)
}

// Count 查询用户总条数
func (m *defaultUserModel) Count(ctx context.Context) (int64, error) {
	query := "SELECT COUNT(1) FROM users"
	var total int64
	err := m.conn.QueryRowCtx(ctx, &total, query)
	return total, err
}

// FindPage 分页查询用户列表（按创建时间倒序）
func (m *defaultUserModel) FindPage(ctx context.Context, offset, limit int) ([]*User, error) {
	var users []*User
	query := `
		SELECT id, username, password, email, phone, nickname, role_id, created_at, updated_at, deleted_at
		FROM users 
		ORDER BY created_at DESC 
		LIMIT ?, ?
	`
	// 调用QueryRowsCtx：参数依次为ctx、接收结果的切片指针、SQL、参数
	err := m.conn.QueryRowsCtx(ctx, &users, query, offset, limit)
	if err != nil {
		return nil, fmt.Errorf("%w: 分页查询失败: %v", errorx.ErrFindPageFailed, err)
	}
	return users, nil
}
